Skip to content

fix: return UnsupportedOperationError (-32004) when streaming is not supported - #1041

Merged
kabir merged 2 commits into
a2aproject:mainfrom
ez-lbz:fix/streaming-error-code-unsupported
Aug 11, 2026
Merged

fix: return UnsupportedOperationError (-32004) when streaming is not supported#1041
kabir merged 2 commits into
a2aproject:mainfrom
ez-lbz:fix/streaming-error-code-unsupported

Conversation

@ez-lbz

@ez-lbz ez-lbz commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

What changed

1. Streaming-not-supported now returns UnsupportedOperationError (-32004) instead of InvalidRequestError (-32600)

Problem: When the agent card does not advertise streaming() capability, the JSON-RPC, gRPC, and REST handlers rejected streaming calls with InvalidRequestError (code -32600, "invalid request"), while other SDKs return UnsupportedOperationError (code -32004, "operation not supported"). -32600 is the wrong semantic for a valid-but-unavailable operation and diverges from the other SDKs.

Fix (transport/jsonrpc/src/main/java/org/a2aproject/sdk/transport/jsonrpc/handler/JSONRPCHandler.java):

  • onMessageSendStream and onSubscribeToTask now emit new UnsupportedOperationError(null, "Streaming is not supported by the agent", null) (message preserved, code now -32004). Removed the now-unused InvalidRequestError import.

Fix (transport/grpc/src/main/java/org/a2aproject/sdk/transport/grpc/handler/GrpcHandler.java):

  • sendStreamingMessage and subscribeToTask now call handleError(responseObserver, new UnsupportedOperationError()); the gRPC status therefore maps from INVALID_ARGUMENT to UNIMPLEMENTED. Updated the method javadoc accordingly.

Fix (transport/rest/src/main/java/org/a2aproject/sdk/transport/rest/handler/RestHandler.java):

  • sendStreamingMessage and subscribeToTask now build the error response with new UnsupportedOperationError(null, "Streaming is not supported by the agent", null). HTTP status stays 400; the error reason changes from INVALID_REQUEST to UNSUPPORTED_OPERATION (via A2AErrorCodes.UNSUPPORTED_OPERATION).

Fix (tests updated in lockstep):

  • JSONRPCHandlerTest (testStreamingNotSupportedErrorOnSendMessageStream, testStreamingNotSupportedErrorOnSubscribeToTask): assert UnsupportedOperationError instead of InvalidRequestError.
  • GrpcHandlerTest (testStreamingNotSupportedError, testStreamingNotSupportedErrorOnSubscribeToTask): assert gRPC Status.Code.UNIMPLEMENTED instead of INVALID_ARGUMENT.
  • RestHandlerTest (testSendStreamingMessageNotSupported): assert reason UNSUPPORTED_OPERATION instead of INVALID_REQUEST.

Behavior change: the JSON-RPC error code for streaming-not-supported changes from -32600 to -32004; the gRPC status changes from INVALID_ARGUMENT to UNIMPLEMENTED; the REST error reason changes from INVALID_REQUEST to UNSUPPORTED_OPERATION (HTTP status remains 400). The error message is unchanged.

Note: the compat-0.3 module (legacy 0.3-spec compatibility shim) has its own copies of the handlers with InvalidRequestError for this path; it was intentionally left unchanged as it is outside the scope of the current transports.

Testing

  • mvn -pl transport/jsonrpc,transport/grpc,transport/rest test124 tests run, 0 failures, 1 skipped (BUILD SUCCESS): JSON-RPC 48 (1 skipped), gRPC 40, REST 36.

@kabir kabir left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @ez-lbz thanks! A few small issues.

Also, there is a pre-existing spec mismatch on gRPC status code. The A2A spec table (section 5.4) maps UnsupportedOperationError to gRPC FAILED_PRECONDITION, but A2AErrorCodes.UNSUPPORTED_OPERATION in this SDK maps it to UNIMPLEMENTED.

The PR's test correctly asserts UNIMPLEMENTED based on the SDK's current mapping, so this is consistent internally — but the SDK itself diverges from the spec on this particular gRPC status. This is not introduced by this PR, just something Claude found.

I've opened #1051 to address this latter part.

So if you just add the strings to the error constructor calls we should be good :-)

StreamObserver<org.a2aproject.sdk.grpc.StreamResponse> responseObserver) {
if (!getAgentCardInternal().capabilities().streaming()) {
handleError(responseObserver, new InvalidRequestError());
handleError(responseObserver, new UnsupportedOperationError());

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe here pass in "Streaming is not supported by the agent" like for the other transports?

StreamObserver<org.a2aproject.sdk.grpc.StreamResponse> responseObserver) {
if (!getAgentCardInternal().capabilities().streaming()) {
handleError(responseObserver, new InvalidRequestError());
handleError(responseObserver, new UnsupportedOperationError());

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe here pass in "Streaming is not supported by the agent" like for the other transports?

…orts

The JSON-RPC and REST transports report
'Streaming is not supported by the agent' when the agent card does not
advertise streaming; the gRPC transport used the bare default message.
Use the same message in sendStreamingMessage and subscribeToTask.
@ez-lbz

ez-lbz commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

Thanks! Both gRPC error constructors now pass the same "Streaming is not supported by the agent" message as the JSON-RPC and REST transports, and the gRPC transport tests pass (40 tests, 0 failures). Appreciate the heads-up on the pre-existing gRPC status mapping divergence (now tracked in #1051) — agreed it's out of scope here.

@kabir
kabir merged commit 5819196 into a2aproject:main Aug 11, 2026
13 checks passed
@kabir

kabir commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Thanks @ez-lbz

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants